package com.cooldatasoft.taskManager.component;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;

import com.cooldatasoft.domain.model.Project;
import com.cooldatasoft.domain.service.UserProjectRolesService;
import com.cooldatasoft.security.TaskManagerSecurityManager;
import com.cooldatasoft.support.git.CommitInfoWrapper;
import com.cooldatasoft.support.git.FileNodeInterface;
import com.cooldatasoft.support.git.JavaGitManager;
import com.vaadin.annotations.AutoGenerated;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.NativeButton;
import com.vaadin.ui.Table;
import com.vaadin.ui.TreeTable;
import com.vaadin.ui.VerticalLayout;

@Configurable(preConstruction = true)
public class SourceControlView extends CustomComponent {
	@AutoGenerated
	private VerticalLayout mainLayout;

	@AutoGenerated
	private NativeButton refreshButton;

	@AutoGenerated
	private HorizontalLayout lowerHorizontal;

	@AutoGenerated
	private VerticalLayout leftPane;

	@AutoGenerated
	private Table commitsTable;

	@AutoGenerated
	private Label commitLabel;

	@AutoGenerated
	private VerticalLayout rightPane;

	@AutoGenerated
	private TreeTable treeTable;

	@AutoGenerated
	private Label repositoryLabel;

	@AutoGenerated
	private VerticalLayout upperVertical;

	@AutoGenerated
	private HorizontalLayout buttonLayout;

	@AutoGenerated
	private NativeButton createDeleteButton;

	@AutoGenerated
	private Label infoLabel;

	/*- VaadinEditorProperties={"grid":"RegularGrid,20","showGrid":true,"snapToGrid":true,"snapToObject":true,"movingGuides":false,"snappingDistance":10} */

	

	/*- VaadinEditorProperties={"grid":"RegularGrid,20","showGrid":true,"snapToGrid":true,"snapToObject":true,"movingGuides":false,"snappingDistance":10} */

	

	/*- VaadinEditorProperties={"grid":"RegularGrid,20","showGrid":true,"snapToGrid":true,"snapToObject":true,"movingGuides":false,"snappingDistance":10} */

	

	/*- VaadinEditorProperties={"grid":"RegularGrid,20","showGrid":true,"snapToGrid":true,"snapToObject":true,"movingGuides":false,"snappingDistance":10} */

	

	/*- VaadinEditorProperties={"grid":"RegularGrid,20","showGrid":true,"snapToGrid":true,"snapToObject":true,"movingGuides":false,"snappingDistance":10} */

	

	/*- VaadinEditorProperties={"grid":"RegularGrid,20","showGrid":true,"snapToGrid":true,"snapToObject":true,"movingGuides":false,"snappingDistance":10} */

	private static final long serialVersionUID = 1L;
	
	@Autowired
	private UserProjectRolesService uprService;
	@Autowired
	private TaskManagerSecurityManager securityManager;

	// header constants of TreeTable
	private static final String FILE_NAME_PROPERTY = "Name";
	private static final String FILE_SIZE_PROPERTY = "Size";
	private static final String LAST_MODIFIED_PROPERTY = "Last Modified";

	// header constants of TreeTable
	private static final String USER_NAME_PROPERTY = "Name";
	private static final String USER_EMAIL_PROPERTY = "Email";
	private static final String COMMIT_DATE_PROPERTY = "Commited";

	private Project myCurrentProject;
	private String repositoryPathPrefix;
	private String projectName;
	private long projectId;

	/**
	 * The constructor should first build the main layout, set the composition
	 * root and then do any custom initialization.
	 * 
	 * The constructor will not be automatically regenerated by the visual
	 * editor.
	 */
	public SourceControlView(Project project) {
		buildMainLayout();
		setCompositionRoot(mainLayout);

		// ====== User defined calls ======//

		this.myCurrentProject = project;
		try {
			repositoryPathPrefix = System.getProperty("user.name") + "@"
					+ InetAddress.getLocalHost().getHostName() + ":";
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
		this.projectName = project.getName().replace(" ", "-");
		this.projectId = project.getIdProject();

		// ====== UI adjustments =========//
		addListenerToCDbutton();
		addListenerToRbutton();
		
		prepareUI();
	}

	private void prepareUI() {
		prepareButtons();
		prepareUpperLayout();
		prepareTreeTable();
		prepareCommitsTable();
	}

	@SuppressWarnings("serial")
	private void addListenerToRbutton() {
		refreshButton.addListener(new ClickListener() {
			@Override
			public void buttonClick(ClickEvent event) {
				prepareUI();
			}
		});		
	}

	@SuppressWarnings("serial")
	private void addListenerToCDbutton() {
		createDeleteButton.addListener(new ClickListener() {
			@Override
			public void buttonClick(ClickEvent event) {
				if (existsProject()) {
					JavaGitManager.getInstance().deleteRepository(projectName, projectId);
				} else {
					JavaGitManager.getInstance().createRepository(projectName, projectId);
				}
				prepareUI();
			}
		});
	}

	private void prepareButtons() {
		if (isManager()) {
			createDeleteButton.setEnabled(true);
			if (existsProject()) {
				createDeleteButton.setCaption("Delete repository");
			} else {
				createDeleteButton.setCaption("Create repository");
			}
			
		} else {
			createDeleteButton.setEnabled(false);			
		}
	}
	
	private boolean isManager() {
		return uprService
				.getUserProjectRolesByIdUserAndIdProject(myCurrentProject,
						securityManager.getCurrentUser()).getIdRole()
				.getIdRole() == 1L;
	}

	private void prepareUpperLayout() {
		if (existsProject()) {
			infoLabel.setValue("Git repository URI for your project is: " + repositoryPathPrefix + projectName 
					+ (isManager() ? "\nAs manager you can delete repository by hitting \'Delete repository\' button" : ""));
		} else {
			if (isManager()) {
				infoLabel.setValue("As manager you can create repository for your team by hitting button \'Create repository\'.");
			} else {
				infoLabel.setValue("Manager of your project is able to create a repository for your team which you can review here than.");
			}
		}
	}

	private void prepareCommitsTable() {
		commitsTable.removeAllItems();
		commitsTable.addContainerProperty(USER_NAME_PROPERTY, String.class, "");
		commitsTable
				.addContainerProperty(USER_EMAIL_PROPERTY, String.class, "");
		commitsTable.addContainerProperty(COMMIT_DATE_PROPERTY, Date.class,
				Calendar.getInstance().getTime());

		if (existsProject()) {
			commitsTable.setEnabled(true);
			fillCommitsTable();
		} else {
			commitsTable.setEnabled(false);
		}
	}

	private void fillCommitsTable() {
		ArrayList<CommitInfoWrapper> commits = JavaGitManager.getInstance()
				.getAllCommitsInfo(projectName, projectId);
		Collections.sort(commits, new Comparator<CommitInfoWrapper>() {
			@Override
			public int compare(CommitInfoWrapper o1, CommitInfoWrapper o2) {
				return (int) (o1.getDate().getTime() - o2.getDate().getTime());
			}
		});

		int i = 1;
		for (CommitInfoWrapper commit : commits) {
			commitsTable.addItem(
					new Object[] { commit.getName(), commit.getEmail(),
							commit.getDate() }, i++);
		}
	}

	private void prepareTreeTable() {
		treeTable.removeAllItems();
		treeTable.addContainerProperty(FILE_NAME_PROPERTY, String.class, "");
		treeTable
				.addContainerProperty(FILE_SIZE_PROPERTY, String.class, "0 KB");
		treeTable.addContainerProperty(LAST_MODIFIED_PROPERTY, Date.class,
				Calendar.getInstance().getTime());

		if (existsProject()) {
			treeTable.setEnabled(true);
			FileNodeInterface root = JavaGitManager.getInstance()
					.getRepositoryStructureForProject(projectName, projectId);
			fillTreeTable(root, null);
		} else {
			treeTable.setEnabled(false);
		}
	}

	private boolean existsProject() {
		return JavaGitManager.getInstance()
				.existProject(projectName, projectId);
	}

	private void fillTreeTable(FileNodeInterface root, Object parent) {
		Object fileNode;

		if (root.isDirectory()) {
			List<FileNodeInterface> children = root.getChildren();
			fileNode = treeTable.addItem(new Object[] { root.getName(), "",
					root.lastModified() }, null);
			treeTable.setChildrenAllowed(fileNode, true);

			for (FileNodeInterface child : children) {
				fillTreeTable(child, fileNode);
			}
		} else {
			fileNode = treeTable.addItem(
					new Object[] { root.getName(),
							String.format("%.2f", root.getSize()) + "KB",
							root.lastModified() }, null);
			treeTable.setChildrenAllowed(fileNode, false);
		}

		if (parent != null) {
			treeTable.setParent(fileNode, parent);
		}
	}

	@AutoGenerated
	private VerticalLayout buildMainLayout() {
		// common part: create layout
		mainLayout = new VerticalLayout();
		mainLayout.setImmediate(false);
		mainLayout.setWidth("100%");
		mainLayout.setHeight("100%");
		mainLayout.setMargin(true);
		mainLayout.setSpacing(true);
		
		// top-level component properties
		setWidth("100.0%");
		setHeight("100.0%");
		
		// upperVertical
		upperVertical = buildUpperVertical();
		mainLayout.addComponent(upperVertical);
		
		// lowerHorizontal
		lowerHorizontal = buildLowerHorizontal();
		mainLayout.addComponent(lowerHorizontal);
		mainLayout.setExpandRatio(lowerHorizontal, 1.0f);
		
		// refreshButton
		refreshButton = new NativeButton();
		refreshButton.setStyleName("defaultBtn");
		refreshButton.setCaption("Refresh");
		refreshButton.setImmediate(true);
		refreshButton.setWidth("-1px");
		refreshButton.setHeight("-1px");
		mainLayout.addComponent(refreshButton);
		mainLayout.setComponentAlignment(refreshButton, Alignment.MIDDLE_LEFT);
		
		return mainLayout;
	}

	@AutoGenerated
	private VerticalLayout buildUpperVertical() {
		// common part: create layout
		upperVertical = new VerticalLayout();
		upperVertical.setImmediate(false);
		upperVertical.setWidth("100.0%");
		upperVertical.setHeight("120px");
		upperVertical.setMargin(false);
		
		// infoLabel
		infoLabel = new Label();
		infoLabel.setCaption("Repository info");
		infoLabel.setImmediate(false);
		infoLabel.setWidth("100.0%");
		infoLabel.setHeight("100.0%");
		infoLabel.setValue("");
		infoLabel.setStyleName("source");
		upperVertical.addComponent(infoLabel);
		upperVertical.setExpandRatio(infoLabel, 1.0f);
		upperVertical.setComponentAlignment(infoLabel, Alignment.MIDDLE_LEFT);
		
		// buttonLayout
		buttonLayout = buildButtonLayout();
		upperVertical.addComponent(buttonLayout);
		upperVertical.setComponentAlignment(buttonLayout, new Alignment(24));
		
		return upperVertical;
	}

	@AutoGenerated
	private HorizontalLayout buildButtonLayout() {
		// common part: create layout
		buttonLayout = new HorizontalLayout();
		buttonLayout.setImmediate(false);
		buttonLayout.setWidth("100.0%");
		buttonLayout.setHeight("-1px");
		buttonLayout.setMargin(false);
		
		// createDeleteButton
		createDeleteButton = new NativeButton();
		createDeleteButton.setStyleName("defaultBtn");
		createDeleteButton.setCaption("Create repository");
		createDeleteButton.setImmediate(true);
		createDeleteButton.setWidth("-1px");
		createDeleteButton.setHeight("-1px");
		buttonLayout.addComponent(createDeleteButton);
		buttonLayout.setComponentAlignment(createDeleteButton,Alignment.MIDDLE_LEFT);
		
		return buttonLayout;
	}

	@AutoGenerated
	private HorizontalLayout buildLowerHorizontal() {
		// common part: create layout
		lowerHorizontal = new HorizontalLayout();
		lowerHorizontal.setImmediate(false);
		lowerHorizontal.setWidth("100.0%");
		lowerHorizontal.setHeight("100.0%");
		lowerHorizontal.setMargin(false);
		lowerHorizontal.setSpacing(true);
		
		// rightPane
		rightPane = buildRightPane();
		lowerHorizontal.addComponent(rightPane);
		lowerHorizontal.setExpandRatio(rightPane, 6.0f);
		
		// leftPane
		leftPane = buildLeftPane();
		lowerHorizontal.addComponent(leftPane);
		lowerHorizontal.setExpandRatio(leftPane, 4.0f);
		
		return lowerHorizontal;
	}

	@AutoGenerated
	private VerticalLayout buildRightPane() {
		// common part: create layout
		rightPane = new VerticalLayout();
		rightPane.setImmediate(false);
		rightPane.setWidth("100.0%");
		rightPane.setHeight("100.0%");
		rightPane.setMargin(false);
		
		// repositoryLabel
		repositoryLabel = new Label();
		repositoryLabel.setImmediate(false);
		repositoryLabel.setWidth("-1px");
		repositoryLabel.setHeight("-1px");
		repositoryLabel.setValue("Browse repository");
		repositoryLabel.setStyleName("sourceLabel");
		rightPane.addComponent(repositoryLabel);
		
		// treeTable
		treeTable = new TreeTable();
		treeTable.setImmediate(false);
		treeTable.setWidth("100.0%");
		treeTable.setHeight("100.0%");
		rightPane.addComponent(treeTable);
		rightPane.setExpandRatio(treeTable, 1.0f);
		rightPane.setComponentAlignment(treeTable, new Alignment(48));
		
		return rightPane;
	}

	@AutoGenerated
	private VerticalLayout buildLeftPane() {
		// common part: create layout
		leftPane = new VerticalLayout();
		leftPane.setImmediate(false);
		leftPane.setWidth("100.0%");
		leftPane.setHeight("100.0%");
		leftPane.setMargin(false);
		
		// commitLabel
		commitLabel = new Label();
		commitLabel.setImmediate(false);
		commitLabel.setWidth("-1px");
		commitLabel.setHeight("-1px");
		commitLabel.setValue("Browse commit history");
		commitLabel.setStyleName("sourceLabel");
		leftPane.addComponent(commitLabel);
		
		// commitsTable
		commitsTable = new Table();
		commitsTable.setImmediate(false);
		commitsTable.setWidth("100.0%");
		commitsTable.setHeight("100.0%");
		leftPane.addComponent(commitsTable);
		leftPane.setExpandRatio(commitsTable, 1.0f);
		leftPane.setComponentAlignment(commitsTable, new Alignment(48));
		
		return leftPane;
	}

}
